﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using LinqKit;
using Project.Model.EF6.Base;

namespace Project.Data.Repository
{
    public class DbContextRepository<TContext> : IDbContextRepository<TContext>
        where TContext : DbContext
    {
        private TContext _context;
        public DbContextFactory<TContext> DbContextFactory = new DbContextFactory<TContext>();

        public TContext Context
        {
            get
            {
                return _context = _context ?? (_context = DbContextFactory.GetDbContext());
            }
        }

        #region 通用增删改查

        #region 非原始sql语句方式

        /// <summary>
        ///     新增
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="isSave">是否提交</param>
        /// <returns>返回受影响行数</returns>
        public virtual bool Add<T>(T entity, bool isSave = true) where T : ModelBase
        {
            Context.Entry(entity).State = EntityState.Added;
            if (isSave) return Context.SaveChanges() > 0;
            return true;
        }

        /// <summary>
        ///     批量插入实体记录集合
        /// </summary>
        /// <param name="entity">实体记录集合</param>
        /// <param name="isSave"> 是否执行保存 </param>
        /// <returns> 操作影响的行数 </returns>
        public virtual bool Add<T>(IEnumerable<T> entity, bool isSave = true) where T : ModelBase
        {
            foreach (T t in entity)
            {
                Context.Entry(t).State = EntityState.Added;
            }
            if (isSave) return Context.SaveChanges() > 0;
            return true;
        }


        /// <summary>
        ///     修改
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="isSave">是否提交</param>
        /// <returns>返回受影响行数</returns>
        public virtual bool Update<T>(T entity, bool isSave = true) where T : ModelBase
        {
            Context.Set<T>().Attach(entity);
            Context.Entry(entity).State = EntityState.Modified;
            Context.Entry(entity).Property("ROW_CREATE_DATE").IsModified = false;
            if (isSave) return Context.SaveChanges() > 0;
            return true;
        }

        /// <summary>
        ///     修改
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="fileds">更新的字段</param>
        /// <param name="isSave">是否提交</param>
        /// <returns>返回受影响行数</returns>
        public virtual bool Update<T>(T entity, List<string> fileds, bool isSave = true) where T : ModelBase
        {
            Context.Set<T>().Attach(entity);
            var setEntry = ((IObjectContextAdapter)Context).ObjectContext.
                         ObjectStateManager.GetObjectStateEntry(entity);
            foreach (var t in fileds)
            {
                setEntry.SetModifiedProperty(t);
            }
            if (isSave) return Context.SaveChanges() > 0;
            return true;
        }


        /// <summary>
        ///     修改
        /// </summary>
        /// <param name="entity">实体集合</param>
        /// <param name="isSave">是否提交</param>
        /// <returns>返回受影响行数</returns>
        public virtual bool Update<T>(IEnumerable<T> entity, bool isSave = true) where T : ModelBase
        {
            foreach (T t in entity)
            {
                Context.Set<T>().Attach(t);
                Context.Entry(t).State = EntityState.Modified;
                Context.Entry(t).Property("ROW_CREATE_DATE").IsModified = false;
            }
            if (isSave) return Context.SaveChanges() > 0;
            return true;
        }

        /// <summary>
        /// 树形属性生成
        /// </summary>
        /// <param name="entity">实体</param>
        /// <returns>返回受影响行数</returns>

        public virtual T GetWrapIdTreeModel<T>(T entity) where T : TreeBase
        {
            var type = typeof(T);
            string keyId = type.GetProperties().First(l => l.CustomAttributes.Any(c => c.ToString().IndexOf(".KeyAttribute") > -1)).Name;
            object keyValue = type.GetProperty(keyId).GetValue(entity, null);
            var parentId = entity.PARENT_ID;
            if (parentId == 0)
            {
                entity.LEAF_LEVEL = 0;
                entity.ID_TREE = "." + keyValue + ".";
            }
            else
            {
                var parentModel = Find<T>(parentId);
                string parentIdTree = parentModel.ID_TREE;
                entity.LEAF_LEVEL = short.Parse((parentIdTree.Split('.').Length - 2).ToString());
                entity.ID_TREE = parentIdTree + keyValue + ".";
            }
            return entity;
        }


        /// <summary>
        ///     删除
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="isSave">是否提交</param>
        /// <returns>返回受影响行数</returns>
        public virtual bool Delete<T>(T entity, bool isSave = true) where T : ModelBase
        {
            Context.Set<T>().Attach(entity);
            Context.Entry(entity).State = EntityState.Deleted;
            if (isSave) return Context.SaveChanges() > 0;
            return true;
        }

        /// <summary>
        ///     根据条件删除
        /// </summary>
        /// <param name="deleWhere">删除条件</param>
        /// <param name="isSave">是否提交</param>
        /// <returns>返回受影响行数</returns>
        public virtual bool Delete<T>(Expression<Func<T, bool>> deleWhere, bool isSave = true) where T : ModelBase
        {
            var entitys = Context.Set<T>().Where(deleWhere);
            foreach (var e in entitys)
            {
                Context.Set<T>().Remove(e);
            }
            //entitys.ForEach(m => Context.Entry(m).State = EntityState.Deleted);
            if (isSave) return Context.SaveChanges() > 0;
            return true;
        }

        /// <summary>
        ///     查找单个
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns></returns>
        public virtual T Find<T>(int id) where T : ModelBase
        {
            return Context.Set<T>().Find(id);
        }

        /// <summary>
        ///     查找单个
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns></returns>
        public virtual T Find<T>(string id) where T : ModelBase
        {
            return Context.Set<T>().Find(id);
        }

        /// <summary>
        ///     通过反射查找单个
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns></returns>
        public virtual T FindByType<T>(string id) where T : class
        {
            int key;
            if (int.TryParse(id, out key)) return Context.Set<T>().Find(key);
            return Context.Set<T>().Find(id);
        }

        /// <summary>
        ///     查找单个
        /// </summary>
        /// <param name="seleWhere">查询条件</param>
        /// <returns></returns>
        public virtual T Find<T>(Expression<Func<T, bool>> seleWhere) where T : ModelBase
        {
            return Context.Set<T>().AsExpandable().FirstOrDefault(seleWhere);
        }

        /// <summary>
        ///     获取所有实体集合
        /// </summary>
        /// <returns></returns>
        public virtual List<T> FindAll<T>() where T : ModelBase
        {
            return Context.Set<T>().AsExpandable().ToList();
        }

        /// <summary>
        ///     获取所有实体集合(单个排序)
        /// </summary>
        /// <returns></returns>
        public virtual List<T> FindSortAll<T, TKey>(Expression<Func<T, TKey>> orderWhere, bool isDesc) where T : ModelBase
        {
            return CommonSort(Context.Set<T>().AsExpandable(), orderWhere, isDesc).ToList();
        }

        /// <summary>
        ///  获取实体集合数量
        /// </summary>
        /// <returns></returns>
        public virtual int GetCount<T>(Expression<Func<T, bool>> seleWhere) where T : ModelBase
        {
            return Context.Set<T>().AsExpandable().Count(seleWhere);
        }

        /// <summary>
        ///     获取前几条实体集合(单个排序)
        /// </summary>
        /// <returns></returns>
        public virtual List<T> FindSortAll<T, TKey>(Expression<Func<T, TKey>> orderWhere, bool isDesc, int top) where T : ModelBase
        {
            return CommonSort(Context.Set<T>().AsExpandable(), orderWhere, isDesc).Take(top).ToList();
        }

        /// <summary>
        ///     获取所有实体集合(多个排序)
        /// </summary>
        /// <returns></returns>
        public virtual List<T> FindSortAll<T>(params OrderModelField[] orderByExpression) where T : ModelBase
        {
            return CommonSort(Context.Set<T>().AsExpandable(), orderByExpression).ToList();
        }


        /// <summary>
        ///     获取前几条实体集合(多个排序)
        /// </summary>
        /// <returns></returns>
        public virtual List<T> FindSortAll<T>(int top, params OrderModelField[] orderByExpression) where T : ModelBase
        {
            return CommonSort(Context.Set<T>().AsExpandable(), orderByExpression).Take(top).ToList();
        }

        /// <summary>
        ///     单个排序通用方法
        /// </summary>
        /// <typeparam name="TKey">排序字段</typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="data">要排序的数据</param>
        /// <param name="orderWhere">排序条件</param>
        /// <param name="isDesc">是否倒序</param>
        /// <returns>排序后的集合</returns>
        public virtual IQueryable<T> CommonSort<T, TKey>(IQueryable<T> data, Expression<Func<T, TKey>> orderWhere, bool isDesc)
            where T : ModelBase
        {
            if (isDesc)
            {
                return data.OrderByDescending(orderWhere);
            }
            return data.OrderBy(orderWhere);
        }

        /// <summary>
        ///     根据条件查询实体集合
        /// </summary>
        /// <param name="seleWhere">查询条件 lambel表达式</param>
        /// <returns></returns>
        public virtual List<T> FindAll<T>(Expression<Func<T, bool>> seleWhere) where T : ModelBase
        {
            return Context.Set<T>().AsExpandable().Where(seleWhere).ToList();
        }

        /// <summary>
        ///     根据条件查询实体集合
        /// </summary>
        /// <param name="seleWhere">查询条件 lambel表达式</param>
        /// <param name="conditions"></param>
        /// <returns></returns>
        public virtual List<T> FindAll<T, TValue>(Expression<Func<T, TValue>> seleWhere, IEnumerable<TValue> conditions)
            where T : ModelBase
        {
            return Context.Set<T>().AsExpandable().WhereIn(seleWhere, conditions).ToList();
        }

        /// <summary>
        ///     根据条件查询实体集合(单个字段排序)
        /// </summary>
        /// <param name="seleWhere">查询条件 lambel表达式</param>
        /// <param name="orderWhere"></param>
        /// <param name="isDesc"></param>
        /// <returns></returns>
        public virtual List<T> FindAll<T, TKey>(Expression<Func<T, bool>> seleWhere, Expression<Func<T, TKey>> orderWhere,
            bool isDesc) where T : ModelBase
        {
            return CommonSort(Context.Set<T>().AsExpandable().Where(seleWhere), orderWhere, isDesc).ToList();
        }

        /// <summary>
        ///     根据条件查询实体集合(单个字段排序)
        /// </summary>
        /// <param name="seleWhere">查询条件 lambel表达式</param>
        /// <param name="orderWhere"></param>
        /// <param name="isDesc"></param>
        /// <param name="top"></param>
        /// <returns></returns>
        public virtual List<T> FindAll<T, TKey>(Expression<Func<T, bool>> seleWhere, Expression<Func<T, TKey>> orderWhere,
            bool isDesc, int top) where T : ModelBase
        {
            return CommonSort(Context.Set<T>().AsExpandable().Where(seleWhere), orderWhere, isDesc).Take(top).ToList();
        }

        /// <summary>
        ///     根据条件查询实体集合(多个字段排序)
        /// </summary>
        /// <param name="seleWhere">查询条件 lambel表达式</param>
        /// <param name="orderByExpression"></param>
        /// <returns></returns>
        public virtual List<T> FindAll<T>(Expression<Func<T, bool>> seleWhere, params OrderModelField[] orderByExpression)
            where T : ModelBase
        {
            var results = CommonSort(Context.Set<T>().AsExpandable().Where(seleWhere), orderByExpression);
            return results.ToList();
        }

        /// <summary>
        ///     根据条件查询实体集合(多个字段排序)
        /// </summary>
        /// <param name="seleWhere">查询条件 lambel表达式</param>
        /// <param name="top"></param>
        /// <param name="orderByExpression"></param>
        /// <returns></returns>
        public virtual List<T> FindAll<T>(Expression<Func<T, bool>> seleWhere, int top, params OrderModelField[] orderByExpression)
            where T : ModelBase
        {
            return CommonSort(Context.Set<T>().AsExpandable().Where(seleWhere), orderByExpression).Take(top).ToList();
        }

        /// <summary>
        ///     获取分页集合(无条件无排序)
        /// </summary>
        /// <returns></returns>
        public virtual List<T> FindAllPaged<T, TKey>(int pageIndex, int pageSize, out int totalcount) where T : ModelBase
        {
            totalcount = Context.Set<T>().AsExpandable().Count(); //获取总数
            //需要增加AsExpandable(),否则查询的是所有数据到内存，然后再排序  AsExpandable是linqkit.dll中的方法
            return Context.Set<T>().AsExpandable().Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
        }

        /// <summary>
        ///     获取分页集合(无条件单个排序)
        /// </summary>
        /// <returns></returns>
        public virtual List<T> FindAllPaged<T, TKey>(int pageIndex, int pageSize, Expression<Func<T, TKey>> orderWhere,
            bool isDesc, out int totalcount) where T : ModelBase
        {
            totalcount = Context.Set<T>().AsExpandable().Count(); //获取总数
            //需要增加AsExpandable(),否则查询的是所有数据到内存，然后再排序  AsExpandable是linqkit.dll中的方法
            return
                CommonSort(Context.Set<T>().AsExpandable(), orderWhere, isDesc)
                    .Skip((pageIndex - 1) * pageSize)
                    .Take(pageSize)
                    .ToList();
        }

        /// <summary>
        ///     获取分页集合(无条件多字段排序)
        /// </summary>
        /// <returns></returns>
        public virtual List<T> FindAllPaged<T>(int pageIndex, int pageSize, out int totalcount,
            params OrderModelField[] orderByExpression) where T : ModelBase
        {
            totalcount = Context.Set<T>().AsExpandable().Count(); //获取总数
            //需要增加AsExpandable(),否则查询的是所有数据到内存，然后再排序  AsExpandable是linqkit.dll中的方法
            return
                CommonSort(Context.Set<T>().AsExpandable(), orderByExpression)
                    .Skip((pageIndex - 1) * pageSize)
                    .Take(pageSize)
                    .ToList();
        }

        /// <summary>
        ///     获取分页集合(有条件无排序)
        /// </summary>
        /// <returns></returns>
        public virtual List<T> FindAllPaged<T, TKey>(int pageIndex, int pageSize, Expression<Func<T, bool>> seleWhere,
            out int totalcount) where T : ModelBase
        {
            totalcount = Context.Set<T>().AsExpandable().Where(seleWhere).Count(); //获取总数
            //需要增加AsExpandable(),否则查询的是所有数据到内存，然后再排序  AsExpandable是linqkit.dll中的方法
            return
                Context.Set<T>().AsExpandable().Where(seleWhere).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
        }

        /// <summary>
        ///     获取分页集合(有条件单个排序)
        /// </summary>
        /// <returns></returns>
        public virtual List<T> FindAllPaged<T, TKey>(int pageIndex, int pageSize, Expression<Func<T, bool>> seleWhere,
            Expression<Func<T, TKey>> orderWhere, bool isDesc, out int totalcount) where T : ModelBase
        {
            totalcount = Context.Set<T>().AsExpandable().Where(seleWhere).Count(); //获取总数
            //需要增加AsExpandable(),否则查询的是所有数据到内存，然后再排序  AsExpandable是linqkit.dll中的方法
            return
                CommonSort(Context.Set<T>().AsExpandable().Where(seleWhere), orderWhere, isDesc)
                    .Skip((pageIndex - 1) * pageSize)
                    .Take(pageSize)
                    .ToList();
        }

        /// <summary>
        ///     获取分页集合(有条件多字段排序)
        /// </summary>
        /// <returns></returns>
        public virtual List<T> FindAllPaged<T>(int pageIndex, int pageSize, Expression<Func<T, bool>> seleWhere,
            out int totalcount, params OrderModelField[] orderModelFiled) where T : ModelBase
        {
            totalcount = Context.Set<T>().AsExpandable().Where(seleWhere).Count(); //获取总数
            //需要增加AsExpandable(),否则查询的是所有数据到内存，然后再排序  AsExpandable是linqkit.dll中的方法
            return
                CommonSort(Context.Set<T>().AsExpandable().Where(seleWhere), orderModelFiled)
                    .Skip((pageIndex - 1) * pageSize)
                    .Take(pageSize)
                    .ToList();
        }

        /// <summary>
        ///     获取分页集合(有条件多字段排序)
        /// </summary>
        /// <returns></returns>
        public virtual PageList<T> ToPageList<T>(int pageIndex, int pageSize, Expression<Func<T, bool>> seleWhere,
            out int totalcount, params OrderModelField[] orderModelFiled) where T : ModelBase
        {
            totalcount = Context.Set<T>().AsExpandable().Where(seleWhere).Count(); //获取总数
            //需要增加AsExpandable(),否则查询的是所有数据到内存，然后再排序  AsExpandable是linqkit.dll中的方法

            var items = CommonSort(Context.Set<T>().AsExpandable().Where(seleWhere), orderModelFiled)
                .Skip((pageIndex - 1) * pageSize)
                .Take(pageSize);
            return new PageList<T>
            {
                Items = items
                    .ToList(),
                CurrentPage = pageIndex,
                PageSize = pageSize,
                TotalNum = totalcount,
            };
        }

        /// <summary>
        ///     获取分页集合(有条件多字段排序)
        /// </summary>
        /// <returns></returns>
        public virtual PageList<T> ToPageList2<T>(int pageIndex, int pageSize, string sql,
            out int totalcount, Expression<Func<T, bool>> seleWhere) where T : ModelBase
        {
            totalcount = Context.Set<T>().AsExpandable().Where(seleWhere).Count(); //获取总数
                                                                                   //需要增加AsExpandable(),否则查询的是所有数据到内存，然后再排序  AsExpandable是linqkit.dll中的方法

            var list = QueryList<T>(sql);
            return new PageList<T>
            {
                Items = list,
                CurrentPage = pageIndex,
                PageSize = pageSize,
                TotalNum = totalcount,
            };
        }


        /// <summary>
        ///     获取分页集合(传值List)
        /// </summary>
        /// <returns></returns>
        public virtual PageList<T> ToPageList<T>(int pageIndex, int pageSize, List<T> list,
            out int totalcount, params OrderModelField[] orderModelFiled) where T : ModelBase
        {
            totalcount = list.Count(); //获取总数
            //需要增加AsExpandable(),否则查询的是所有数据到内存，然后再排序  AsExpandable是linqkit.dll中的方法
            return new PageList<T>
            {
                Items = list.Skip((pageIndex - 1) * pageSize)
                    .Take(pageSize)
                    .ToList(),
                CurrentPage = pageIndex,
                PageSize = pageSize,
                TotalNum = totalcount,
            };
        }


        /// <summary>
        ///     多个排序通用方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data">要排序的数据</param>
        /// <param name="orderByExpression">字典集合(排序条件,是否倒序)</param>
        /// <returns>排序后的集合</returns>
        public static IQueryable<T> CommonSort<T>(IQueryable<T> data, params OrderModelField[] orderByExpression)
            where T : class
        {
            //创建表达式变量参数
            ParameterExpression parameter = Expression.Parameter(typeof(T), "o");

            if (orderByExpression != null && orderByExpression.Length > 0)
            {
                for (int i = 0; i < orderByExpression.Length; i++)
                {
                    //根据属性名获取属性
                    PropertyInfo property = typeof(T).GetProperty(orderByExpression[i].PropertyName);
                    //创建一个访问属性的表达式
                    MemberExpression propertyAccess = Expression.MakeMemberAccess(parameter, property);
                    LambdaExpression orderByExp = Expression.Lambda(propertyAccess, parameter);

                    string orderName;
                    if (i > 0)
                    {
                        orderName = orderByExpression[i].IsDesc ? "ThenByDescending" : "ThenBy";
                    }
                    else
                        orderName = orderByExpression[i].IsDesc ? "OrderByDescending" : "OrderBy";

                    MethodCallExpression resultExp = Expression.Call(typeof(Queryable), orderName,
                        new[] { typeof(T), property.PropertyType },
                        data.Expression, Expression.Quote(orderByExp));

                    data = data.Provider.CreateQuery<T>(resultExp);
                }
            }
            return data;
        }

        #endregion

        #region 原始sql操作

        /// <summary>
        ///     执行操作(通过sql语句进行添加，修改，删除功能)
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="paras"></param>
        public virtual void ExecuteSql(string sql, params object[] paras)
        {
            Context.Database.ExecuteSqlCommand(sql, paras);
        }

        /// <summary>
        ///   返回受影响的条数(通过sql语句进行添加，修改，删除功能并返回)
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="paras"></param>
        public virtual int StrExecuteSql(string sql, params object[] paras)
        {
            return Context.Database.ExecuteSqlCommand(sql, paras);
        }


        /// <summary>
        ///     查询列表(通过sql语句进行查找功能。查询的字段必须和传入的Model完全匹配,单个字段T可设为string)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <param name="paras"></param>
        /// <returns></returns>
        public virtual List<T> QueryList<T>(string sql, params object[] paras) where T : class
        {
            return Context.Database.SqlQuery<T>(sql, paras).ToList();
        }

        /// <summary>
        ///     查询单个(通过sql语句进行查找功能。查询的字段必须和传入的Model完全匹配,单个字段T可设为string)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <param name="paras"></param>
        /// <returns></returns>
        public virtual T QuerySingle<T>(string sql, params object[] paras) where T : class
        {
            return Context.Database.SqlQuery<T>(sql, paras).FirstOrDefault();
        }

        /// <summary>
        ///     查询单个
        /// </summary>
        /// <param name="t"></param>
        /// <param name="sql"></param>
        /// <returns></returns>
        public virtual object QuerySingle(Type t, string sql)
        {
            return Context.Database.SqlQuery(t, sql);
        }

        /// <summary>
        ///     执行事务
        /// </summary>
        /// <param name="lsSql"></param>
        /// <param name="lsParas"></param>
        public virtual void ExecuteTransaction(List<String> lsSql, List<Object[]> lsParas)
        {
            using (DbContextTransaction tran = Context.Database.BeginTransaction())
            {
                try
                {
                    for (int i = 0; i < lsSql.Count; i++)
                    {
                        if (lsParas != null && lsParas.Count > 0)
                        {
                            Context.Database.ExecuteSqlCommand(lsSql[i], lsParas[i]);
                        }
                    }
                    foreach (String item in lsSql)
                    {
                        Context.Database.ExecuteSqlCommand(item);
                    }

                    tran.Commit();
                }
                catch (Exception)
                {
                    tran.Rollback();
                    throw;
                }
            }
        }

        #endregion

        #region 通用属性

        /// <summary>
        ///     获取数据库服务器当前时间。
        /// </summary>
        public DateTime ServerTime
        {
            get
            {
                const string sql = "SELECT GETDATE()";
                var objServerTime = Context.Database.SqlQuery<DateTime>(sql).ToList();
                return Convert.ToDateTime(objServerTime[0]);
            }
        }

        /// <summary>
        ///     获取数据库版本。
        /// </summary>
        public string DatabaseVersion
        {
            get
            {
                const string sql = "SELECT @@VERSION AS Version";
                var objVersion = Context.Database.SqlQuery<string>(sql).ToList();
                return Convert.ToString(objVersion[0]);
            }
        }
        #endregion

        #endregion
    }

    public static class QueryableExtension
    {
        /// <summary>
        ///     扩展方法  支持 in 操作
        /// </summary>
        /// <typeparam name="TEntity">需要扩展的对象类型</typeparam>
        /// <typeparam name="TValue">in 的值类型</typeparam>
        /// <param name="source">需要扩展的对象</param>
        /// <param name="valueSelector">值选择器 例如c=>c.UserId</param>
        /// <param name="values">值集合</param>
        /// <returns></returns>
        public static IQueryable<TEntity> WhereIn<TEntity, TValue>(this IQueryable<TEntity> source,
            Expression<Func<TEntity, TValue>> valueSelector,
            IEnumerable<TValue> values)
        {
            if (null == valueSelector)
            {
                throw new ArgumentNullException(nameof(valueSelector));
            }
            if (null == values)
            {
                throw new ArgumentNullException(nameof(values));
            }
            var p = valueSelector.Parameters.Single();
            var enumerable = values as TValue[] ?? values.ToArray();
            if (!enumerable.Any())
            {
                return source;
            }
            var equals =
                enumerable.Select(
                    value =>
                        (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value, typeof(TValue))));
            var body = equals.Aggregate(Expression.Or);
            return source.Where(Expression.Lambda<Func<TEntity, bool>>(body, p));
        }
    }
}